#include "Define.h"
#include "S32K146.h"


typedef struct                 /*发送接收报文结构体*/
{
    uint8_t EDL;     /* EDL=1 CAN FD format frame*/
    uint8_t BRS;     /* BRS=1: Bit rate is switched inside msg */
    uint8_t ESI;
    uint8_t CODE;    /* CODE=0xC: Activate msg buf to transmit */
    uint8_t SRR;     /* SRR=1 Tx frame (not req'd for std ID) */
    uint8_t IDE;     /* IDE=0: Standard ID */
    uint8_t RTR;     /* RTR = 0: data, not remote tx request frame*/
    uint8_t DLC;
    uint8_t PRIO;
    uint32_t ID;
    uint8_t pData[64];                    
    uint32_t timestamp;
}CANFD_FrameStruct;
CANFD_FrameStruct canFDTxMsg, canFDRxMsg;

#define CAN_WMBn_CS_CODE_MASK                    0x0F000000u
#define CAN_WMBn_CS_CODE_SHIFT                   24u
#define CAN_WMBn_CS_CODE_WIDTH                   4u
#define CAN_WMBn_CS_CODE(x)                      (((uint32_t)(((uint32_t)(x))<<CAN_WMBn_CS_CODE_SHIFT))&CAN_WMBn_CS_CODE_MASK)

/*
 * ===================================================
 * Function :  FLEXCAN0_init For CANFD 
 * 1. Configure Header phase = 500Kbps bit time, 
 * 2. Configure data phase = 2 MHz bit time 
 * 3. Individual Rx Mask for per mailbox
 * 4. MB4~MB6 Individual mask receives interrupt 
 * 5. disable frame self reception 
 * 6. Enable CRC fix for ISO CAN FD 
 * Coder :  djf
 * Date/Time :  2020/08/20 
 * ===================================================
 */

#define TXMB3      3u
#define TXMB4      4u
#define TXMB5      5u
#define TXMB6      6u


#define MSG_BUF_SIZE  18    /* Msg Buffer Size. (2 words hdr + 16 words data  = 18 words) */


void FLEXCAN0FD_init(void)                   //CANFD
{   
    uint32_t i = 0;     

    PCC->PCCn[PCC_FlexCAN0_INDEX] |= PCC_PCCn_CGC_MASK; /* CGC=1: enable clock to FlexCAN0 */

    CAN0->MCR |= CAN_MCR_SOFTRST_MASK;      //Soft Reset
	CAN0->MCR &= ~CAN_MCR_SOFTRST_MASK;
    
    CAN0->MCR |= CAN_MCR_MDIS_MASK;         /* MDIS=1: Disable module before selecting clock */
    CAN0->CTRL1 |= CAN_CTRL1_CLKSRC_MASK;   /* CLKSRC=1: Clock Source = BUSCLK (40 MHz) */
    CAN0->MCR &= ~CAN_MCR_MDIS_MASK;        /* MDIS=0; Enable the FlexCAN module. (Sets FRZ, HALT)	*/  
    // After the clock source is selected and the module is enabled (MCR[MDIS] bit negated), FlexCAN automatically enters Freeze mode. In Freeze mode
    // CAN0->MCR |= CAN_MCR_FRZ_MASK;          /*(Sets FRZ, HALT)	*/ 
    while (!((CAN0->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT)) {}
   
    // Step1: Initialize MCR
    CAN0->MCR |= CAN_MCR_IRMQ_MASK // a: IRMQ=1, enable the individual filtering per MB and reception queue features            
              | CAN_MCR_WRNEN_MASK // b: WRNEN=1, enable the warning interrupts
              | CAN_MCR_SRXDIS_MASK // c: SRXDIS=1, disable frame self reception
              //| CAN_MCR_RFEN_MASK // d: RFEN=1, Enable the Rx FIFO, MBs 0 to 5 cannot be used for normal reception and transmission(they have been uesed for the FIFO engine)
              //| CAN_MCR_DMA_MASK// e: DMA=1, dont use DMA
              //f: PNET_EN=0, dont use pretended networking
              | CAN_MCR_AEN_MASK// g: AEN=1, use Tx Abort mechanism
              | CAN_MCR_LPRIOEN_MASK   // h: PRIOEN=1, Local Priority enabled     
              | CAN_MCR_FDEN_MASK     // i: CAN FD is enabled
              //| CAN_MCR_IDAM(0)// IDAM=0, ID Acceptance Mode=Format A: One full ID (standard and extended) per ID filter table element.
              | CAN_MCR_MAXMB(32); // MAXMB = 32    */        
   
    // Step2: Initialize CTRL1 or CBT
    // The CAN bit variables in CTRL1 and in CBT are stored in the same register.
    /* Configure nominal phase: 500 KHz bit time, 40 MHz Sclock */ /* Prescaler = CANCLK / Sclock = 40 MHz / 40 MHz = 1 */   
    CAN0->CBT |= CAN_CBT_BTF_MASK
              | CAN_CBT_EPRESDIV(1)     /* EPRESDIV = Prescaler - 1 = 0 */
              | CAN_CBT_EPSEG2(15)		/* EPSEG2 = 15 */
              | CAN_CBT_EPSEG1(15)		/* EPSEG1 = 15 */
              | CAN_CBT_EPROPSEG(47)	/* EPROPSEG = 47 */
              | CAN_CBT_ERJW(15);   	/* ERJW = 15 */
                                        /* BITRATEn =Fcanclk /( [(1 + (EPSEG1+1) + (EPSEG2+1) + (EPROPSEG + 1)] x (EPRESDIV+1)) */
                                        /*         = 40 MHz /( [(1 + ( 15   +1) + ( 15   +1) + (   46    + 1)] x (    0   +1)) */
                                        /*         = 40 MHz /( [1+16+16+47] x 1) = 40 MHz /(80x1) = 500 Kz */
                                                                                                                     
    /* Configure data phase: 2 MHz bit time, 40 MHz Sclock */ /* Prescaler = CANCLK / Sclock = 40 MHz / 40 MHz = 1 */
	CAN0->FDCBT |= CAN_FDCBT_FPRESDIV(1)    /* FPRESDIV = Prescaler - 1 = 0 */
                | CAN_CBT_EPSEG2(3)         /* FPSEG2 = 3 */  
                | CAN_CBT_EPSEG1(7)         /* FPSEG1 = 7 */  
                | CAN_CBT_EPROPSEG(7)       /* FPROPSEG = 7 */
                | CAN_CBT_ERJW(3);          /* FRJW = 3 */
                                            /* BITRATEf =Fcanclk /( [(1 + (FPSEG1+1) + (FPSEG2+1) + (FPROPSEG)] x (FPRESDIV+!)) */
                                            /*          = 40 MHz /( [(1 + (  7   +1) + (  3   +1) + (   7    )] x (    0   +1)) */
                                            /*          = 40 MHz /( [1+8+4+7] x 1) = 40 MHz /(20x1) = 40 MHz / 20 = 2 MHz  */      
                                                                                                                           
    CAN0->CTRL1 |= CAN_CTRL1_PRESDIV(0)     // Tq = fcanclk / prediv = 8MHz / 1 = 8MHz
                | CAN_CTRL1_RJW(3)          // RJW: since Phase_Seg2 >=4, RJW+1=4 so RJW=3.
                | CAN_CTRL1_PSEG1(3)        // Phase Segment 1 = PSEG1 + 1
                | CAN_CTRL1_PSEG2(3)        // Phase Segment 2 = PSEG2 + 1
                | CAN_CTRL1_PROPSEG(6)      // Propagation Segment = PROPSEG + 1
                | CAN_CTRL1_SMP(1)    
                | CAN_CTRL1_LBUF(1);        // LBUF=1, Lowest number bufferNum is transmitted first.(MCR[LPRIOEN] + LBUF <= transmit priority)
   
    CAN0->FDCTRL = CAN_FDCTRL_FDRATE_MASK	/* FDRATE = 1, Bit Rate Switch Enable */
                  |CAN_FDCTRL_MBDSR0(3)	    /* MBDSR0=3: Region 0 has 64 bytes data in frame's payload */
                  |CAN_FDCTRL_TDCEN_MASK	/* TDCEN=1: enable Transceiver Delay Compensation */
                  |CAN_FDCTRL_TDCOFF(5);    /* TDCOFF=5: 5 CAN clocks (300us) offset used */                                    
    
    // Step3: Initialize the message buffers    
    // MB & Rx Individual Mask registers are not affected by reset, so they are not initialized automatically.  
    // CAN0: clear 32 message bufferNum x 4 words/msg, buf = 128 words
    // CAN0 contains 32MBs         
    for(i=0; i<128; i++)   //i = Number of Rx FIFO filter elements; Table 53-6. Rx FIFO filter: possible structures
    {   					 /* CAN0: clear 32 msg bufs x 4 words/msg buf = 128 words */
        CAN0->RAMn[i] = 0;   /* Clear msg buf word */
    }    
   
    // Step4: Initialize RXIMRn(Rx Individual Mask registers)
    // In FRZ mode, init CAN0 16 individual msg buf filters . there are total 32MBs for CAN0
    for(i=0; i<16; i++)           /*Individual Rx Masking, the mailbox filter and Rx FIFO ID filter table element in distinct ways.*/
    {         			       
        CAN0->RXIMR[i] = 0xFFFFFFFF;        /* 1b - The corresponding bit in the filter is checked. 0b-The corresponding bit in the filter is "don't care." */
               
    }         // 15D40000
    CAN0->RXMGMASK = 0x1FFFFFFF;//0x1594FFFF;  				/* When MCR[IRMQ] is negated, RXMGMASK is always in effect (the bits in the MG field will mask the mailbox filter bits).*/
                                                /* 1b - The corresponding bit in the filter is checked. 0b-The corresponding bit in the filter is "don't care." */
    CAN0->RX14MASK = 0x1FFFFFFF;
    CAN0->RX15MASK = 0x1FFFFFFF;    
        
    /* Message Buffer 4 - receive setup: Individual Mask*/
	CAN0->RAMn[TXMB4*MSG_BUF_SIZE + 0] = 0xC4000000;  /* Msg Buf 4, word 0: Enable for reception */
                                                      /* EDL=1: Extended Data Length for CAN FD */
                                                      /* BRS = 1: Bit Rate Switch enabled */
                                                      /* ESI = 0: Error state */
                                                      /* CODE=4: MB set to RX inactive */
                                                      /* IDE=0: Standard ID */
                                                      /* SRR, RTR, TIME STAMP = 0: not applicable */
    CAN0->RAMn[TXMB4*MSG_BUF_SIZE + 1] = (0x454 & 0x7FF) << 18;       
    CAN0->RAMn[TXMB5*MSG_BUF_SIZE + 0] = 0xC4000000;
    CAN0->RAMn[TXMB5*MSG_BUF_SIZE + 1] = (0x575 & 0x7FF) << 18;  
    CAN0->RAMn[TXMB6*MSG_BUF_SIZE + 0] = 0xC4000000;
    CAN0->RAMn[TXMB6*MSG_BUF_SIZE + 1] = (0x234 & 0x7FF) << 18;   
 
    // Step5: Set required interrupt mask bits in  IMASK registers CTRL1 / CTRL2 registers                 
    CAN0->IMASK1 |= 0x78;       // Buf 3、4、5、6
	CAN0->CTRL2 |= CAN_CTRL2_ISOCANFDEN_MASK;       /* Enable CRC fix for ISO CAN FD */
	    
    // Step7: nagate HALT   
    CAN0->MCR &= 0xBFFFFFFF;             //disable Freeze mode.
    CAN0->MCR &= ~CAN_MCR_HALT_MASK;       /* Negate HALT bit */ 
             
    while ((CAN0->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) {}
    /* Good practice: wait for FRZACK to clear (not in freeze mode) */
    while ((CAN0->MCR & CAN_MCR_NOTRDY_MASK) >> CAN_MCR_NOTRDY_SHIFT) {}
    /* Good practice: wait for NOTRDY to clear (module ready) */
}

/*************************************************************/
/*****                   CANFD发送函数                   *****/
/*****Coder:   djf                                       *****/
/*****ID:      报文ID                                        */
/*****IDE:     0 标准帧、1 扩展帧                            */
/*****RTR:     0 数据帧、1 远程帧                            */
/*****DLC:     报文数据长度(<=15)                            */
/*****PRIO:    报文发送优先级 0最高                          */ 
/***** *CANFD_Frame:    发送结构体指针                       */    
/*************************************************************/

bool FLEXCAN0FD_TX_Frame(CANFD_FrameStruct *CANFD_Frame)
{
    #define Buf_TXMB    0u    /* MBx for transmitting CAN message //Table 53-6. Rx FIFO filter: possible structures */
    
    uint8_t i = 0;    
    uint8_t code = 0;
    uint8_t bufferNum = 0;
    
    //4. Read back the CODE field to check if the transmission was aborted or transmitted
    code = (CAN0->RAMn[Buf_TXMB*MSG_BUF_SIZE + 0]&CAN_WMBn_CS_CODE_MASK) >> CAN_WMBn_CS_CODE_SHIFT;
    if(0x80==code)           //MB is not active
    {
        return (false);
    }
    else
    {
    
    }
    //5. Clear the corresponding interrupt flag.
    CAN0->IFLAG1 |= (1 << Buf_TXMB); // Clear CAN0 13 flag without clearing other.
    
    //6. Write the ID register
    /*MB word1*/
    if(!CANFD_Frame->IDE)     // Standard frame
    {
        CAN0->RAMn[Buf_TXMB*MSG_BUF_SIZE + 1] = (CANFD_Frame->PRIO << 29)|((CANFD_Frame->ID&0x7FF) << 18u);  // std id  /*MB word1*/ 
    }
    else                      // Extended frame
    {
        CAN0->RAMn[Buf_TXMB*MSG_BUF_SIZE + 1] = (CANFD_Frame->PRIO << 29)|(CANFD_Frame->ID&0x1FFFFFFF);  // Ext id  /*MB word1*/ 
    }   
    
    //7. Write payload Data bytes.
    if(!CANFD_Frame->RTR)               // Data frame 
    {        
        CAN0->RAMn[Buf_TXMB*MSG_BUF_SIZE + 2] = CAN_RAMn_DATA_BYTE_0(CANFD_Frame->pData[0])      /*MB word2*/             
                                                   | CAN_RAMn_DATA_BYTE_1(CANFD_Frame->pData[1])
                                                   | CAN_RAMn_DATA_BYTE_2(CANFD_Frame->pData[2])
                                                   | CAN_RAMn_DATA_BYTE_3(CANFD_Frame->pData[3]);        
            
        CAN0->RAMn[Buf_TXMB*MSG_BUF_SIZE + 3] = CAN_RAMn_DATA_BYTE_0(CANFD_Frame->pData[4])      /*MB word3*/           
                                                   | CAN_RAMn_DATA_BYTE_1(CANFD_Frame->pData[5])
                                                   | CAN_RAMn_DATA_BYTE_2(CANFD_Frame->pData[6])
                                                   | CAN_RAMn_DATA_BYTE_3(CANFD_Frame->pData[7]);
      
        if(8<CANFD_Frame->DLC)
        {                
            if(13>CANFD_Frame->DLC)
            {
                bufferNum = CANFD_Frame->DLC - 8;
            }
            else
            {
                if(13==CANFD_Frame->DLC)
                {
                    bufferNum = 6;
                }
                else
                {
                    bufferNum = 6 + (CANFD_Frame->DLC-13)*4;                        
                }                    
            }
            for(i=0; i<bufferNum; i++)
            {
                CAN0->RAMn[Buf_TXMB*MSG_BUF_SIZE + 4 + i] = CAN_RAMn_DATA_BYTE_0(CANFD_Frame->pData[i*4+8])              
                                                          | CAN_RAMn_DATA_BYTE_1(CANFD_Frame->pData[i*4+8+1])
                                                          | CAN_RAMn_DATA_BYTE_2(CANFD_Frame->pData[i*4+8+2])
                                                          | CAN_RAMn_DATA_BYTE_3(CANFD_Frame->pData[i*4+8+3]);
            }
        }
        else
        {
            
        }
        
    }
    else                                // Remote frame
    {
    
    }
   
    //8. Configure the Control and Status word with the desired configuration     
    CAN0->RAMn[Buf_TXMB*MSG_BUF_SIZE + 0] = ((uint32_t)CANFD_Frame->EDL<<31)|((uint32_t)CANFD_Frame->BRS<<30)|((uint32_t)CANFD_Frame->ESI<<29);    /*MB word0*/       
    CAN0->RAMn[Buf_TXMB*MSG_BUF_SIZE + 0] |= CAN_WMBn_CS_IDE(CANFD_Frame->IDE)
                                               | CAN_WMBn_CS_RTR(CANFD_Frame->RTR)            
                                               | CAN_WMBn_CS_SRR(CANFD_Frame->SRR)            
                                               | CAN_WMBn_CS_DLC(CANFD_Frame->DLC)
                                               | CAN_WMBn_CS_CODE(CANFD_Frame->CODE);  
    
    return (true);

}

/*************************************************************/
/*****                   CANFD接收函数                   *****/
/*****Coder:   djf                                       *****/
/*****ID:      报文ID                                        */
/*****IDE:     0 标准帧、1 扩展帧                            */
/*****RTR:     0 数据帧、1 远程帧                            */
/*****DLC:     报文数据长度(<=15)                            */
/*****PRIO:    报文发送优先级 0最高                          */ 
/***** *FDrxMsg:    接收结构体指针                           */    
/*************************************************************/


void FLEXCAN0FD_RX_Frame(CANFD_FrameStruct *FDrxMsg)
{
    uint8_t Buf_RXMB = 5u;    /* MB for receiving CAN message*/    
    uint8_t i = 0;
    uint8_t bufferNum = 0;
          
    if(0<CAN0->IFLAG1)
    {
        for(i=1; i<32; i++)
        {
            if(1==((CAN0->IFLAG1>>i)&0x00000001))
            {
                Buf_RXMB = i; 
                break; 
            }
            else
            {
            
            } 
        }
    }
    else
    {
    
    }        
    
    // when received CAN message by FIFO (MB0~5), interrupt flag set by IFLAG5(not IFLAG0~4)
    if(0<CAN0->IFLAG1)
    {
        // 1. Read the Control and Status word
        FDrxMsg->IDE = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+0] & CAN_WMBn_CS_IDE_MASK) >> CAN_WMBn_CS_IDE_SHIFT;
        FDrxMsg->RTR = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+0] & CAN_WMBn_CS_RTR_MASK) >> CAN_WMBn_CS_RTR_SHIFT;
        FDrxMsg->DLC = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+0] & CAN_WMBn_CS_DLC_MASK) >> CAN_WMBn_CS_DLC_SHIFT;
        FDrxMsg->SRR = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+0] & CAN_WMBn_CS_SRR_MASK) >> CAN_WMBn_CS_SRR_SHIFT;
        FDrxMsg->CODE = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+0] & CAN_WMBn_CS_CODE_MASK) >> CAN_WMBn_CS_CODE_SHIFT;
        FDrxMsg->timestamp = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+0] & 0x000FFFF);
                
        // 2. Read the ID field
        if(!FDrxMsg->IDE)
        {
            FDrxMsg->ID = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+1] >> 18) & 0x7FF;      // std id
        }
        else
        {
            FDrxMsg->ID = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+1] & 0x1FFFFFFF);       // Ext id
        }
         
        for(i=0; i<64; i++)
        {
            FDrxMsg->pData[i] = 0;           //Clear cache
        }  
        // 3. Read the data field.
        if(!FDrxMsg->RTR)
        {                                                              
            FDrxMsg->pData[0] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+2] >> 24) & 0xFF;
            FDrxMsg->pData[1] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+2] >> 16) & 0xFF;
            FDrxMsg->pData[2] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+2] >> 8) & 0xFF;
            FDrxMsg->pData[3] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+2]) & 0xFF;
            FDrxMsg->pData[4] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+3] >> 24) & 0xFF;
            FDrxMsg->pData[5] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+3] >> 16) & 0xFF;
            FDrxMsg->pData[6] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+3] >> 8) & 0xFF;
            FDrxMsg->pData[7] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE+3]) & 0xFF;                   
                             
            if(8<FDrxMsg->DLC)
            {
                if(13>FDrxMsg->DLC)
                {
                    bufferNum = FDrxMsg->DLC - 8;
                }
                else
                {
                    if(13==FDrxMsg->DLC)
                    {
                        bufferNum = 6;
                    }
                    else
                    {
                        bufferNum = 6 + (FDrxMsg->DLC-13)*4;                        
                    }                    
                }
                
                for(i=0; i<bufferNum; i++)
                {
                    FDrxMsg->pData[i*4+8] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE + 4 + i] >> 24) & 0xFF;
                    FDrxMsg->pData[i*4+8+1] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE + 4 + i] >> 16) & 0xFF;
                    FDrxMsg->pData[i*4+8+2] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE + 4 + i] >> 8) & 0xFF;
                    FDrxMsg->pData[i*4+8+3] = (CAN0->RAMn[Buf_RXMB*MSG_BUF_SIZE + 4 + i]) & 0xFF;
                }                                
                
            }
            else
            {                
                
            }
            
        }
        else               //  Ext id  no data
        {
                     
        }
        
        // 4. Read the RXFIR register
        (void)CAN0->RXFIR;
       
        // 5. Clear the Frames Available in Rx FIFO interrupt by writing one to IFLAG1             
        // CAN0->IFLAG1 |= 0x20;       /* Clear CAN0 MB5 flag*/
        CAN0->IFLAG1 |= 0xFFFFFFFF;
    }
    else
    {
    
    }      
    
}

/*********************************************************************
 * 函数原型：void CAN0_ORed_0_15_MB_IRQHandler(void)
 * 功        能：CAN0中断服务器
 * 输入参数：无
 * 返回参数：无
 *
 * 其他说明：
*********************************************************************/

void CAN0_ORed_0_15_MB_IRQHandler(void)
{      
    FLEXCAN0FD_RX_Frame(&canFDRxMsg);    
}



